import { getCell, getColumnByCell, getRowIdentity, gcds, lcms } from "./util";
import { hasClass, addClass, removeClass } from "element-ui/src/utils/dom";
import ElCheckbox from "element-ui/packages/checkbox";
// import ElTooltip from 'element-ui/packages/tooltip';
import debounce from "throttle-debounce/debounce";

function renderTableRow(row, $index, columnsHidden, h) {
  return <tr
    style={this.rowStyle ? this.getRowStyle(row, $index) : null}
    key={this.table.rowKey ? this.getKeyOfRow(row, $index) : $index}
    on-dblclick={($event) => this.handleDoubleClick($event, row)}
    on-click={($event) => this.handleClick($event, row)}
    on-contextmenu={($event) => this.handleContextMenu($event, row)}
    on-mouseenter={_ => this.handleMouseEnter($index)}
    on-mouseleave={_ => this.handleMouseLeave()}
    class={[this.getRowClass(row, $index)]}>
    {
      this._l(this.columns, (column, cellIndex) =>
        <td
          class={[column.id, column.align, column.className || "", columnsHidden[cellIndex] ? "is-hidden" : ""]}
          on-mouseenter={($event) => this.handleCellMouseEnter($event, row)}
          on-mouseleave={this.handleCellMouseLeave}>
          {
            column.renderCell.call(this._renderProxy, h, {
              row,
              column,
              $index,
              store: this.store,
              _self: this.context || this.table.$vnode.context
            }, columnsHidden[cellIndex])
          }
        </td>
      )
    }
    {
      !this.fixed && this.layout.scrollY && this.layout.gutterWidth ? <td class="gutter"/> : ""
    }
  </tr>;
}

export default {
  components: {
    ElCheckbox
    // ElTooltip
  },

  props: {
    store: {
      required: true
    },
    stripe: Boolean,
    context: {},
    layout: {
      required: true
    },
    rowClassName: [String, Function],
    rowStyle: [Object, Function],
    fixed: String,
    highlight: Boolean
  },

  render(h) {
    const columnsHidden = this.columns.map((column, index) => this.isColumnHidden(index));
    return (
      <table
        class="el-table__body"
        cellspacing="0"
        cellpadding="0"
        border="0">
        <colgroup>
          {
            this._l(this.columns, column =>
              <col
                name={ column.id }
                width={ column.realWidth || column.width }
              />)
          }
        </colgroup>
        <tbody>
          {
            this._l(this.data, (row, $index) => {
              const rowCount = this.getNumsOfRowField(row);
              return [
                this._l(rowCount, lineNo => <tr>{
                  this._l(this.columns, (column, cellIndex) => {
                    const rowSpan = this.getRowSpan(row, column);
                    return lineNo % rowSpan === 1 || (rowSpan === 1) ? <td rowspan={rowSpan} class={[column.id, column.align, column.className || "", columnsHidden[cellIndex] ? "is-hidden" : ""]}
                      on-mouseenter={($event) => this.handleCellMouseEnter($event, row)}
                      on-mouseleave={this.handleCellMouseLeave}>
                      {
                        column.renderCell.call(this._renderProxy, h, {
                          row,
                          column,
                          $index,
                          index: rowSpan === 1 ? lineNo - 1 : parseInt(lineNo / rowSpan),
                          store: this.store,
                          _self: this.context || this.table.$vnode.context
                        }, columnsHidden[cellIndex])
                      }
                    </td> : null;
                  })
                }</tr>),
                // renderTableRow.call(this, row, $index, columnsHidden, h),
                // ,
                this.store.states.expandRows.indexOf(row) > -1
                  ? (<tr>
                    <td colspan={ this.columns.length } class="el-table__expanded-cell">
                      { this.table.renderExpanded ? this.table.renderExpanded(h, { row, $index, store: this.store }) : ""}
                    </td>
                  </tr>)
                  : ""
              ]
            }).concat(
              this._self.$parent.$slots.append
            ).concat(
              <el-tooltip effect={ this.table.tooltipEffect } placement="top" ref="tooltip" content={ this.tooltipContent }></el-tooltip>
            )
          }
        </tbody>
      </table>
    );
  },

  watch: {
    "store.states.hoverRow"(newVal, oldVal) {
      if (!this.store.states.isComplex) return;
      const el = this.$el;
      if (!el) return;
      const rows = el.querySelectorAll("tbody > tr.el-table__row");
      const oldRow = rows[oldVal];
      const newRow = rows[newVal];
      if (oldRow) {
        removeClass(oldRow, "hover-row");
      }
      if (newRow) {
        addClass(newRow, "hover-row");
      }
    },
    "store.states.currentRow"(newVal, oldVal) {
      if (!this.highlight) return;
      const el = this.$el;
      if (!el) return;
      const data = this.store.states.data;
      const rows = el.querySelectorAll("tbody > tr.el-table__row");
      const oldRow = rows[data.indexOf(oldVal)];
      const newRow = rows[data.indexOf(newVal)];
      if (oldRow) {
        removeClass(oldRow, "current-row");
      } else if (rows) {
        [].forEach.call(rows, row => removeClass(row, "current-row"));
      }
      if (newRow) {
        addClass(newRow, "current-row");
      }
    }
  },

  computed: {
    table() {
      return this.$parent;
    },

    data() {
      return this.store.states.data;
    },

    columnsCount() {
      return this.store.states.columns.length;
    },

    leftFixedCount() {
      return this.store.states.fixedColumns.length;
    },

    rightFixedCount() {
      return this.store.states.rightFixedColumns.length;
    },

    columns() {
      return this.store.states.columns;
    }
  },

  data() {
    return {
      tooltipContent: ""
    };
  },

  created() {
    // Object.defineProperty(this.store.states, 'columns', {
    //   enumerable: true,
    //   configurable: true,
    //   get() {
    //     return [];
    //   },
    //   set(newVal) {
    //     this.store.states.columns = newVal;
    //   }
    // });
    this.activateTooltip = debounce(50, tooltip => tooltip.handleShowPopper());
  },

  methods: {
    getNumsOfRowField(row) {
      // 所有字段长度的最小公倍数
      var fieldCounts = [];
      Object.keys(row).forEach((field) => {
        if (Object.prototype.toString.call(row[field]) === "[object Array]") {
          fieldCounts.push(row[field].length);
        } else {
          fieldCounts.push(1);
        }
      });
      return lcms(...fieldCounts);
    },

    getRowSpan(row, column) {
      const field = row[column.property];
      let length = 1;
      if (field && Object.prototype.toString.call(field) === "[object Array]") {
        length = field.length;
      }
      return this.getNumsOfRowField(row) / length;
    },

    getKeyOfRow(row) {
      const rowKey = this.table.rowKey;
      if (rowKey) {
        return getRowIdentity(row, rowKey);
      }
      return index;
    },

    isColumnHidden(index) {
      if (this.fixed === true || this.fixed === "left") {
        return index >= this.leftFixedCount;
      } else if (this.fixed === "right") {
        return index < this.columnsCount - this.rightFixedCount;
      } else {
        return (index < this.leftFixedCount) || (index >= this.columnsCount - this.rightFixedCount);
      }
    },

    getRowStyle(row, index) {
      const rowStyle = this.rowStyle;
      if (typeof rowStyle === "function") {
        return rowStyle.call(null, row, index);
      }
      return rowStyle;
    },

    getRowClass(row, index) {
      const classes = ["el-table__row"];

      if (this.stripe && index % 2 === 1) {
        classes.push("el-table__row--striped");
      }
      const rowClassName = this.rowClassName;
      if (typeof rowClassName === "string") {
        classes.push(rowClassName);
      } else if (typeof rowClassName === "function") {
        classes.push(rowClassName.call(null, row, index) || "");
      }

      return classes.join(" ");
    },

    handleCellMouseEnter(event, row) {
      const table = this.table;
      const cell = getCell(event);

      if (cell) {
        const column = getColumnByCell(table, cell);
        const hoverState = table.hoverState = { cell, column, row };
        table.$emit("cell-mouse-enter", hoverState.row, hoverState.column, hoverState.cell, event);
      }

      // 判断是否text-overflow, 如果是就显示tooltip
      const cellChild = event.target.querySelector(".cell");

      if (hasClass(cellChild, "el-tooltip") && cellChild.scrollWidth > cellChild.offsetWidth) {
        const tooltip = this.$refs.tooltip;

        this.tooltipContent = cell.innerText;
        tooltip.referenceElm = cell;
        tooltip.$refs.popper.style.display = "none";
        tooltip.doDestroy();
        tooltip.setExpectedState(true);
        this.activateTooltip(tooltip);
      }
    },

    handleCellMouseLeave(event) {
      const tooltip = this.$refs.tooltip;
      if (tooltip) {
        tooltip.setExpectedState(false);
        tooltip.handleClosePopper();
      }
      const cell = getCell(event);
      if (!cell) return;

      const oldHoverState = this.table.hoverState;
      this.table.$emit("cell-mouse-leave", oldHoverState.row, oldHoverState.column, oldHoverState.cell, event);
    },

    handleMouseEnter(index) {
      this.store.commit("setHoverRow", index);
    },

    handleMouseLeave() {
      this.store.commit("setHoverRow", null);
    },

    handleContextMenu(event, row) {
      this.handleEvent(event, row, "contextmenu");
    },

    handleDoubleClick(event, row) {
      this.handleEvent(event, row, "dblclick");
    },

    handleClick(event, row) {
      this.store.commit("setCurrentRow", row);
      this.handleEvent(event, row, "click");
    },

    handleEvent(event, row, name) {
      const table = this.table;
      const cell = getCell(event);
      let column;
      if (cell) {
        column = getColumnByCell(table, cell);
        if (column) {
          table.$emit(`cell-${name}`, row, column, cell, event);
        }
      }
      table.$emit(`row-${name}`, row, event, column);
    },

    handleExpandClick(row) {
      this.store.commit("toggleRowExpanded", row);
    }
  }
};
